package com.since.algorithm.search;

import java.lang.reflect.Field;
import java.util.Collections;
import java.util.List;

/**
 * Created by Sincerity on 2020/5/16.
 * 描述：二分法查找泛型数组,找到就会返回需要查找的值
 * 查找目标元素在集合中的位置{@link #search(Object obj)}
 */
public class RecursionDichotomy<T extends Comparable<T>> {
    private String searchKey; //对比的属性名
    private List<T> data;
    private int currentIndex = -1;

    public RecursionDichotomy(String searchKey, List<T> data) {
        this.searchKey = searchKey;
        this.data = data;
        Collections.sort(this.data);
    }

    public String getSearchKey() throws Exception {
        if (null == searchKey || "".equals(searchKey)) {
            throw new Exception("searchKey is null !");
        }
        return searchKey;
    }

    public void setSearchKey(String searchKey) {
        this.searchKey = searchKey;
    }

    //对外调用接口排序属性为字节型
    public T search(Object key) throws Exception {
        return binarySearch(data, key);
    }

    //对外调用接口排序属性为短整型
    public T search(Short key) throws Exception {
        return binarySearch(data, key);
    }

    //对外调用接口排序属性为整型
    public T search(Integer key) throws Exception {
        return binarySearch(data, key);
    }

    //对外调用接口排序属性为长整型
    public T search(Long key) throws Exception {
        return binarySearch(data, key);
    }

    //对外调用接口排序属性为单精度浮点型
    public T search(Float key) throws Exception {
        return binarySearch(data, key);
    }

    //对外调用接口排序属性为双精度浮点型
    public T search(Double key) throws Exception {
        return binarySearch(data, key);
    }

    //对外调用接口排序属性为字符串
    public T search(String key) throws Exception {
        return binarySearch(data, key);
    }

    private T binarySearch(List<T> data, Object key) throws Exception {
        int middle = data.size() / 2;
        String typeName = key.getClass().getTypeName();
        String type = typeName.substring(typeName.lastIndexOf(".") + 1);
        T midValue = data.get(middle);
        //反射获取T排序属性对应的值
        Field field = midValue.getClass().getDeclaredField(this.getSearchKey());
        field.setAccessible(true);//允许反射私有属性
        int rin;
        switch (type) {
            case "Byte":
                Byte by = field.getByte(midValue);
                rin = by.compareTo((Byte) key);
            case "Short":
                Short sh = field.getShort(midValue);
                rin = sh.compareTo((Short) key);
                break;
            case "Integer":
                Integer in = field.getInt(midValue);
                rin = in.compareTo((Integer) key);
                break;
            case "Long":
                Long lo = field.getLong(midValue);
                rin = lo.compareTo((Long) key);
                break;
            case "Float":
                Float fl = field.getFloat(midValue);
                rin = fl.compareTo((Float) key);
                break;
            case "Double":
                Double dou = field.getDouble(midValue);
                rin = dou.compareTo((Double) key);
                break;
            case "String":
                String st = (String) field.get(midValue);
                rin = st.compareTo((String) key);
                break;
            default:
                rin = 2;
                break;
        }
        //传入的属性值小于集合中间对象排序值，取集合左边子集合传入当前方法
        if (rin > 0) {
            return binarySearch(data.subList(0, middle), key);
            //传入的属性值大于集合中间对象排序值，取集合右边子集合传入当前方法
        } else if (rin < 0) {
            return binarySearch(data.subList(middle, data.size()), key);
            //传入的属性值等于当前中间值时，返回该对象。
        } else {
            currentIndex = middle;
            return midValue;
        }
    }

    /**
     * 如果找到需要查找的元素就会返回当前元素的下标,没有返回-1;
     *
     * @return 元素在集合中的索引 ,没找到返回-1;
     */
    public int getCurrentIndex() {
        return currentIndex;
    }
}
